
#include "Weapon.h"
#include "Bomb.h"
#include "../Utils/Timer.h"
#include "../World.h"
#include "../Map.h"
#include "../Explosion.h"
#include "../Shockwave.h"
#include "../Graphics/TextureManager.h"

#include <cassert>
#include <GL/gl.h>
#include <iostream>


BombProjectile::BombProjectile(Player *parent_player, Vector2D target,
                               float speed, unsigned count) : 
    parent_player(parent_player),
    target(target),
    is_active(true) {

    assert(parent_player != NULL);

    fire_direction = parent_player->getShip()->getHeading();
    fire_direction.normalise();

    position = parent_player->getShip()->getPosition() + parent_player->getShip()->getSize()*1.5f*fire_direction;
    velocity = parent_player->getShip()->getHeading()*speed + parent_player->getShip()->getVelocity();

    

    perp_fire_direction = fire_direction;
    perp_fire_direction.rotate(90.0f);

    texture_id = TextureManager::instance().loadTexture("data/bomb2.png");
}

BombProjectile::~BombProjectile(){

}

void BombProjectile::render(void){
    glPushMatrix();

    Vector2D vec = -1.0f * fire_direction;
    vec.scale(0.3f);

    Vector2D offset = perp_fire_direction;
    offset.scale(0.055f);

    glEnable(GL_ALPHA_TEST);
    glAlphaFunc(GL_GREATER, 0.0f);

    //glEnable(GL_BLEND);
    //glBlendFunc(GL_SRC_ALPHA, GL_ONE);
    
    glEnable(GL_TEXTURE_2D);
    TextureManager::instance().bindTexture(texture_id);

    glBegin(GL_QUADS);
      glColor3f(1.0f, 1.0f, 1.0f);
      glTexCoord2f(0.0f, 0.0f);
      glVertex3f(position.x+offset.x, position.y+offset.y, 0.0f);

      glTexCoord2f(0.0f, 1.0f);
      glVertex3f(position.x-offset.x, position.y-offset.y, 0.0f);
      

      glColor3f(0.7f, 0.7f, 0.7f);
      glTexCoord2f(1.0f, 1.0f);
      glVertex3f(position.x+vec.x-offset.x, position.y+vec.y-offset.y, 0.0f);
      
      glTexCoord2f(1.0f, 0.0f);
      glVertex3f(position.x+vec.x+offset.x, position.y+vec.y+offset.y, 0.0f);
    glEnd();

    glDisable(GL_TEXTURE_2D);
    glDisable(GL_ALPHA_TEST);

    glPopMatrix();
}

void BombProjectile::update(void){
    prev_position = position;
    position.add(velocity * Timer::secondsSinceLastFrame());

    if((position - target).length() < 0.3f){
        explode();
    }
}

bool BombProjectile::active(void){
    return is_active;
}

bool BombProjectile::resolveCollision(Ship *ship){
    assert(ship != NULL);

    if(ship != parent_player->getShip() && 
      (ship->getPosition()-position).length() < ship->getSize()){
        explode();
        return true;
    }
 
    return false;
}

bool BombProjectile::resolveCollision(Weapon *weapon){
    return false;
}

bool BombProjectile::resolveCollision(Map *map){
    Vector2D cp_normal, cp;

    if(map->collideRaySegment(prev_position, position, cp_normal, cp)){
        explode();
        return true;
    }

    if(!map->pointInsideMap(position)){
        is_active = false;
    }    

    return false;
}

void BombProjectile::explode(void){
    Shockwave *s = new Shockwave(position, 4.0f, 0.5f, 1.0f, 0.6f, 0.6f, 0.6f);
    World::instance().addObject(s);

    Explosion *e = new Explosion(5, position, Vector2D(0.0f, 0.0f), 
                      0.0f, 0.4f,
                      1.0f, 1.0f, 1.0f, 
                      1.4f, 0.5f, "data/explosion1.png");
    
    World::instance().addObject(e);
    is_active = false;

    // Go through all ships and damage them if they are in range.
    std::vector<WorldObject*> ships = World::instance().getAllObjectsOfType(SHIP_WOBJECT);
    for(unsigned i = 0; i < ships.size(); i++){
        assert(ships[i] != NULL);
        Ship *pship = (Ship*)(ships[i]);
        Vector2D ship_pos = pship->getPosition();
        if((ship_pos - position).length() < 2.0f){
            Vector2D to_explosion = position - ship_pos;
            to_explosion.normalise();
            pship->impact(ship_pos + pship->getSize()*to_explosion);
        }
        
    }
}



Bomb::Bomb(int ammo_count, int lifetime, Ship *pship) :
    WeaponGenerator(ammo_count, lifetime, 4.0f, pship),
    bomb_sound(Sound::instance().load("data/Sounds/blaster1.mp3")),
    num_bombs_fired(0) {

    assert(parent_ship != NULL);
}

Bomb::~Bomb(){

}

bool Bomb::shouldDiscard(void){
    // Has the weapon expired because it has been picked up too long ago?
    if(lifetime > 0 && (spawn_time + lifetime*1000) > Timer::currentTicks()){
        return true;
    }
    // Has the weapon expired because its ammo count is exhausted?
    else if(ammo_count == 0){
        return true;
    }
    else{
        return false;
    }
}

bool Bomb::fire(void) {
    // Figure out if we CAN fire first
    if(ammo_count != 0 && // have we run out of ammo?
      (Timer::currentTicks() - time_of_last_fire)/1000.0f >= rate_of_fire && // did we fire too recently?
      parent_ship->getEnergy() > 10){

        time_of_last_fire = Timer::currentTicks();
        ammo_count--;

        
        BombProjectile *bomb = new BombProjectile(parent_ship->getControllingPlayer(), 
                                                  parent_ship->getCrosshairPos(), 
                                                  1.3f, num_bombs_fired);
        World::instance().addObject(bomb);
        //Sound::instance().play(bolt_sound);
        num_bombs_fired++;

        parent_ship->getControllingPlayer()->incShotsFired();
        parent_ship->drainEnergy(50);
        return true;
    }
    else{
        return false;
    }
}

